#!/usr/bin/env python3
import os
import sys
import gzip
import re
from pathlib import Path

def read_apt_history_logs(root_dir):
    """读取APT历史日志文件，返回所有行内容"""
    log_files = []
    apt_log_dir = os.path.join(root_dir, 'var', 'log', 'apt')
    
    if not os.path.isdir(apt_log_dir):
        print(f"警告：APT日志目录不存在: {apt_log_dir}", file=sys.stderr)
        return []
    
    for f in os.listdir(apt_log_dir):
        if f.startswith('history.log'):
            log_files.append(os.path.join(apt_log_dir, f))
    
    log_files.sort(key=lambda x: os.path.getmtime(x), reverse=True)
    
    all_lines = []
    
    for log_file in log_files:
        try:
            if log_file.endswith('.gz'):
                with gzip.open(log_file, 'rt', encoding='utf-8', errors='ignore') as f:
                    lines = f.readlines()
            else:
                with open(log_file, 'r', encoding='utf-8', errors='ignore') as f:
                    lines = f.readlines()
            
            all_lines.extend(lines)
        except Exception as e:
            print(f"警告：无法读取日志文件 {log_file}: {str(e)}", file=sys.stderr)
    
    return all_lines

def parse_apt_history(lines):
    """解析APT历史日志，返回用户主动安装的软件包列表"""
    installed_packages = set()
    current_block = []
    
    for line in lines:
        line = line.strip()
        if not line:
            if current_block:
                # 处理完整的日志块
                process_apt_block(current_block, installed_packages)
                current_block = []
            continue
        current_block.append(line)
    
    # 处理最后一个块（如果文件不以空行结尾）
    if current_block:
        process_apt_block(current_block, installed_packages)
    
    return sorted(installed_packages)

def process_apt_block(block, installed_packages):
    """处理单个APT日志块，提取安装的软件包"""
    has_install = False
    requested_by = False
    commandline = ""
    
    for line in block:
        if line.startswith("Commandline:"):
            commandline = line[len("Commandline:"):].strip()
        if line.startswith("Install:"):
            has_install = True
        if line.startswith('Requested-By:'):
            requested_by = True
    
    # 检查是否Requested-By
    if not requested_by:
        return
    
    # 检查是否是安装操作
    if not has_install or not commandline:
        return
    
    # 检查命令是否包含install
    if "install" not in commandline.lower():
        return

    # 提取安装的包名
    parts = commandline.split()
    try:
        install_index = [p.lower() for p in parts].index("install")
        packages = parts[install_index + 1:]
        
        # 过滤掉选项和参数
        filtered_packages = []
        for p in packages:
            if p.startswith('-'):
                continue
            filtered_packages.append(p)
        
        if filtered_packages:
            for pkg in filtered_packages:
                installed_packages.add(pkg)
    except ValueError:
        pass

def clean_package_name(pkg):
    """清理包名，去除特殊符号和版本信息"""
    # 处理以^开头和$=结尾的包名
    if pkg.startswith('^') and '$=' in pkg:
        # 提取包名部分（^和$=之间的内容）
        pkg = pkg.split('$=', 1)[0][1:]
        # 替换转义的点号
        pkg = pkg.replace('\\.', '.')
    
    return pkg

def categorize_packages(packages):
    """将包分为两类：deb文件安装和apt在线安装"""
    deb_packages = set()
    apt_packages = set()
    
    for pkg in packages:
        # 清理包名
        cleaned_pkg = clean_package_name(pkg)
        
        # 分类
        if cleaned_pkg.endswith('.deb'):
            # 提取纯文件名（去除路径）
            filename = os.path.basename(cleaned_pkg)
            deb_packages.add(filename)
        else:
            apt_packages.add(cleaned_pkg)
    
    return sorted(deb_packages), sorted(apt_packages)

def main():
    if len(sys.argv) != 2:
        print("用法: python3 scan_installed_software.py <被扫描系统的根目录>", file=sys.stderr)
        sys.exit(1)
    
    root_dir = sys.argv[1].rstrip('/')
    print(f"正在扫描系统根目录: {root_dir}")
    
    # 读取APT历史日志
    apt_history_lines = read_apt_history_logs(root_dir)
    print(f"从APT历史日志中读取了 {len(apt_history_lines)} 行记录")
    
    # 解析APT历史日志，获取用户安装的软件包
    apt_packages = parse_apt_history(apt_history_lines)
    
    # 分类和清理包名
    deb_packages, apt_packages = categorize_packages(apt_packages)
    
    # 保存结果到文件
    with open('deb_installed.txt', 'w') as f:
        f.write('\n'.join(deb_packages))
    with open('apt_installed.txt', 'w') as f:
        f.write('\n'.join(apt_packages))
    
    print("\n分类结果:")
    print(f"1. 使用deb文件安装的软件 ({len(deb_packages)}个):")
    print('\n'.join(deb_packages[:5]) + ('\n...' if len(deb_packages) > 5 else ''))
    
    print(f"\n2. 使用apt命令在线安装的软件 ({len(apt_packages)}个):")
    print('\n'.join(apt_packages[:5]) + ('\n...' if len(apt_packages) > 5 else ''))
    
    print("\n结果已保存到:")
    print(" - deb_installed.txt")
    print(" - apt_installed.txt")

if __name__ == '__main__':
    main()